package model;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Analyzes the text of a web page and calculates statistics regarding word
 * count, matches of user input key words, and time spent analyzing.
 * 
 * @author Thomas Nunn
 * @author David Everitt
 * @author Dexter Hu
 * @version TCSS 422 Operating Systems Winter 2014
 */
public class PageAnalyzer implements Runnable {

	/**
	 * Holds the key words from user's input.
	 */
	private List<String> myKeyWords;

	/**
	 * A Map containing already analyzed URLs as keys and web page text as values.
	 */
	private Map<String, ArrayList<String>> myHTML;

	/**
	 * A Map of the user's key words to number of occurrences.
	 */
	private Map<String, Integer> myKeyStats;

	/**
	 * A List of words per page.
	 */
	private List<Integer> myWordsPerPage;

	/**
	 * Holds the number of pages analyzed by this Object.
	 */
	private int myNumberAnalyzed = 0;

	/**
	 * The PageParser
	 */
	private PageParser parser;

	/**
	 * Represents the state of the web crawler, running or stopped.
	 */
	private volatile boolean isRunning = true;

	/**
	 * Gives the status of this Object.
	 */
	private volatile boolean isComplete = false;

	/**
	 * Constructor
	 */
	public PageAnalyzer() {
		super();
		myKeyWords = new ArrayList<>();
		myHTML = new HashMap<>();
		new ArrayList<>();
		myKeyStats = new HashMap<>();
		myWordsPerPage = new ArrayList<>();
	}

	/**
	 * Analyze web pages by counting words and comparing each word with
	 * the user's key words.
	 * 
	 * @param theHTML The Map of URLs and pages to analyze.
	 */
	public synchronized void analyzePage(Map<String, ArrayList<String>> theHTML) {

		for (Map.Entry<String, ArrayList<String>> entry : theHTML.entrySet()) {
			int wordCount = 0;

			for (String word : entry.getValue()) {

				wordCount++;

				for (Map.Entry<String, Integer> keyword : myKeyStats.entrySet()) {

					if (word.equals(keyword.getKey())) {
						keyword.setValue(keyword.getValue() + 1);
					}
				}

			}
			myHTML.put(entry.getKey(), entry.getValue());
			myWordsPerPage.add(wordCount); 
			myNumberAnalyzed++;
		}
	}

	/**
	 * Loads the user inputted key words into the map
	 * 
	 * @param theKeys
	 */
	public void loadKeyWords(List<String> theKeys) {
		myKeyWords.addAll(theKeys);

		for (String str : theKeys) {
			myKeyStats.put(str, 0);
		}
	}

	/**
	 * Resets fields.
	 */
	public void clear() {
		myKeyWords.clear();
		myKeyStats.clear();
		myHTML.clear();
		myWordsPerPage.clear();
		myNumberAnalyzed = 0;
		parser = new PageParser();
		isComplete = false;
		isRunning = true;
	}

	/**
	 * @return a copy of the myKeyStats Map.
	 */
	public synchronized Map<String, Integer> getKeyStats() {
		Map<String, Integer> myCopyKeyStats = new HashMap<>();
		myCopyKeyStats.putAll(myKeyStats);
		return myCopyKeyStats;
	}

	/**
	 * @return a copy of the myKeyWords List.
	 */
	public synchronized List<String> getKeyWords() {
		List<String> myCopyKeyWords = new ArrayList<>(myKeyWords);
		return myCopyKeyWords;
	}

	/**
	 * @return The average words per page.
	 */
	public synchronized double getAvgWordsPerPage() {
		double result = 0.0;
		int size = myWordsPerPage.size();
		if (size > 0) {
			for (Integer c : myWordsPerPage) {
				result += c;
			}
			result = result / size;
		}
		return result;
	}

	/**
	 * @return The number of pages analyzed.
	 */
	public synchronized int getMyNumberAnalyzed() {
		return myNumberAnalyzed;
	}

	/**
	 * @return True if this Analyzer is finished.
	 */
	public synchronized boolean isFinished() {
		return isComplete;
	}

	/**
	 * Stops the run() method.
	 */
	public void stopCrawler() {
		isRunning = false;
		isComplete = true;
	}
	
	/**
	 * @return True if the run() methods is still active.
	 */
	public boolean isRunning() {
		return isRunning;
	}

	/**
	 * Sets this Object's PageParser.
	 * 
	 * @param theParser
	 */
	public void setParser(PageParser theParser) {
		parser = theParser;
	}

	/**
	 * Checks to see if the PageParser is done. If parser is done,
	 * then each URL's contents are analyzed.
	 */
	@Override
	public void run() {

		while (isRunning()) {

			if (parser.getHTMLMap().size() > 0 && !parser.isRunning()) {
				analyzePage(parser.getHTMLMap());

			}
		}
	}
}
